home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 16 code / CollaboDraw / digisig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-24  |  15.6 KB  |  711 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------------------------
  2.  *
  3.  * Simple Sample PowerTalk Application Framework
  4.  *
  5.  * ©1991-1993 Apple Computer
  6.  *
  7.  -------------------------------------------------------------------------------------*/
  8. /*
  9.  * digisig.c -- digital signature stuff
  10.  *
  11.  * change history:
  12.  *
  13.  * SJF        08/23/93        1.0f1        update to final headers, fix comments
  14.  * SJF        03/08/93        1.0b1        initial coding
  15.  *
  16.  */
  17.  
  18. #pragma segment othersegment
  19.  
  20. #ifndef __TYPES__
  21. #include <Types.h>
  22. #endif
  23.  
  24. #ifndef __MENUS__
  25. #include <Menus.h>
  26. #endif
  27.  
  28. #ifndef __FOLDERS__
  29. #include <Folders.h>
  30. #endif
  31.  
  32. #ifndef __FILES__
  33. #include <Files.h>
  34. #endif
  35.  
  36. #ifndef __ERRORS__
  37. #include <Errors.h>
  38. #endif
  39.  
  40. #ifndef __RESOURCES__
  41. #include <Resources.h>
  42. #endif
  43.  
  44. #ifndef __GESTALTEQU__
  45. #include <GestaltEqu.h>
  46. #endif
  47.  
  48. #ifndef __TOOLUTILS__
  49. #include <ToolUtils.h>
  50. #endif
  51.  
  52. #ifndef __DIGITALSIGNATURE__
  53. #include <DigitalSignature.h>
  54. #endif
  55.  
  56. #include "const.h"
  57. #include "mytypes.h"
  58. #include "globals.h"
  59. #include "utils.h"
  60. #include "windowstuff.h"
  61. #include "strconst.h"
  62. #include "mymenus.h"
  63. #include "draw.window.h"
  64. #include "IconSuites.h"
  65.  
  66. #include "digisig.h"
  67.  
  68. #define    kDSIGPattern    7    // we're using the black diagonal lines pattern
  69. #define    kDSIGFrameSize    2    // our pattern outline frame is 2 pixels wide
  70.  
  71. // static globals
  72.  
  73. static short gDSTempRefNum;    // temporary digital signature storage file refnum
  74. static FSSpec gDSTempFSpec;    // temporary digital signature storage file FSSpec
  75.  
  76. // routines
  77.  
  78. /** HasDigiSign
  79.  **
  80.  ** returns true only of Digital Signature package is available and running
  81.  **/
  82. Boolean HasDigiSign(void)
  83. {
  84.     OSErr err;
  85.     long response;
  86.     
  87.     err = Gestalt(gestaltDigitalSignatureVersion,&response);
  88.     if ((err!=noErr) || (response==0))
  89.         return false;
  90.     
  91.     return true;
  92. }
  93.  
  94.  
  95. /** InitDigitalSignatures
  96.  **
  97.  ** called once at launch to set up temporary files for digital signature handling
  98.  **/
  99. OSErr InitDigitalSignatures(void)
  100. {    
  101.     OSErr err;
  102.     
  103.     gShowSigners = false;
  104.     
  105.     err = FindFolder(kOnSystemDisk,kTemporaryFolderType,true,&gDSTempFSpec.vRefNum,
  106.                     &gDSTempFSpec.parID);
  107.     if (err!=noErr)
  108.         return err;
  109.     GetResString((StringPtr)&gDSTempFSpec.name,kTempDSFileID,kTempDSFile);
  110.     
  111.     FSpCreateResFile(&gDSTempFSpec,kAppCreator,'????',smRoman);
  112.     if (ResError()==dupFNErr) {
  113.         FSpDelete(&gDSTempFSpec);
  114.         FSpCreateResFile(&gDSTempFSpec,kAppCreator,'????',smRoman);
  115.     }
  116.     if (ResError()==noErr)
  117.         gDSTempRefNum = FSpOpenResFile(&gDSTempFSpec,fsRdWrPerm);
  118.         
  119.     return ResError();
  120. }
  121.  
  122.  
  123. /** ExitDigitalSignatures
  124.  **
  125.  ** called once at quit to get rid of temporary files for digital signature handling
  126.  **/
  127. void ExitDigitalSignatures(void)
  128. {
  129.     CloseResFile(gDSTempRefNum);
  130.     FSpDelete(&gDSTempFSpec);
  131. }
  132.  
  133.  
  134. /** DSIGSetupSignMenu
  135.  **
  136.  ** called to set up the signatures menu for a particular window- enables and disables items
  137.  **/
  138. void DSIGSetupSignMenu(WInfoPtr infoPtr)
  139. {
  140.     MenuHandle theMenu;
  141.     ShapeListPtr shapeList;
  142.     Boolean gotSigned;
  143.     
  144.     theMenu = GetMHandle(kSignMenu);
  145.  
  146.     if (!gHasDigiSign) {
  147.         DisableItem(theMenu,0);
  148.         return;
  149.     }
  150.     
  151.     EnableAllMenuItems(theMenu);
  152.     
  153.     if (!CheckShapeSelected(infoPtr))
  154.         DisableItem(theMenu,kSignItem);
  155.     
  156.     gotSigned = false;
  157.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  158.         if ((shapeList->isSigned) && (shapeList->selected))
  159.             gotSigned = true;
  160.     }
  161.     if (!gotSigned)
  162.         DisableItem(theMenu,kVerifyItem);
  163.     
  164.     CheckItem(theMenu,kShowSignItem,gShowSigners);
  165. }
  166.  
  167.  
  168. /** DSIGOpenFile
  169.  **
  170.  ** called when a document is opened to get a record of which shapes are signed
  171.  **/
  172. void DSIGOpenFile(WInfoPtr infoPtr)
  173. {
  174.     DigSigListPtr    dsigList,newDSIG;
  175.     ShapeListPtr    shapeList;
  176.     
  177.     dsigList = nil;
  178.     
  179.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  180.         if (shapeList->isSigned) {
  181.             newDSIG = NewPtrChk(sizeof(DigSigList));
  182.             if (MemError()!=noErr)
  183.                 return;
  184.             newDSIG->shape = shapeList;
  185.             newDSIG->signatureID = shapeList->signatureID;
  186.             newDSIG->inTemp = false;
  187.             newDSIG->shouldDelete = false;
  188.             newDSIG->next = dsigList;
  189.             dsigList = newDSIG;
  190.             shapeList->digSig = newDSIG;
  191.         }
  192.         else
  193.             shapeList->digSig = nil;
  194.     }
  195.     
  196.     infoPtr->otherData[kDSIGData] = dsigList;
  197. }
  198.  
  199.  
  200. /** DSIGCloseFile
  201.  **
  202.  ** called when a document is closed in order to remove any digital signatures
  203.  ** from the temporary digital signature file
  204.  **/
  205. void DSIGCloseFile(WInfoPtr infoPtr)
  206. {
  207.     DigSigListPtr dsigList,prevSig;
  208.     short saveResFile;
  209.     Handle resHandle;
  210.     
  211.     saveResFile = CurResFile();
  212.     UseResFile(gDSTempRefNum);
  213.     
  214.     dsigList=infoPtr->otherData[kDSIGData];
  215.     while (dsigList!=nil) {
  216.         if (dsigList->inTemp) {
  217.             SetResLoad(false);
  218.             resHandle = Get1Resource(kSignatureResType,dsigList->signatureID);
  219.             RmveResource(resHandle);
  220.             SetResLoad(true);
  221.         }
  222.         prevSig = dsigList;
  223.         dsigList = dsigList->next;
  224.         DisposPtrChk(prevSig);
  225.     }
  226.     infoPtr->otherData[kDSIGData] = nil;
  227.     
  228.     UpdateResFile(gDSTempRefNum);
  229.     UseResFile(saveResFile);
  230. }
  231.  
  232.  
  233. /** DSIGSaveFile
  234.  **
  235.  ** called when a document is saved in order to flush any digital signatures back to disk
  236.  ** from the temporary digital signature file
  237.  **/
  238. void DSIGSaveFile(WInfoPtr infoPtr,short newResRef,Boolean saveACopy)
  239. {
  240.     short saveResFile,oldResRef;
  241.     short newID;
  242.     DigSigListPtr dsigList,oldSig,prevSig;
  243.     Handle resHandle;
  244.         
  245.     oldResRef = infoPtr->resRefNum;
  246.     saveResFile = CurResFile();
  247.  
  248.     prevSig = nil;
  249.     dsigList=infoPtr->otherData[kDSIGData];
  250.     while (dsigList!=nil) {
  251.         if (dsigList->shouldDelete && (dsigList->inTemp ||
  252.                 (!saveACopy && (oldResRef==newResRef)))) {
  253.         
  254.             // delete sig resource
  255.             
  256.             if (dsigList->inTemp)
  257.                 UseResFile(gDSTempRefNum);
  258.             else
  259.                 UseResFile(oldResRef);
  260.             SetResLoad(false);
  261.             resHandle = Get1Resource(kSignatureResType,dsigList->signatureID);
  262.             RmveResource(resHandle);
  263.             SetResLoad(true);
  264.             
  265.             // delete old dsig object from list
  266.             
  267.             if (prevSig)
  268.                 prevSig->next = dsigList->next;
  269.             else
  270.                 infoPtr->otherData[kDSIGData] = dsigList->next;
  271.             
  272.             oldSig = dsigList;
  273.             dsigList = dsigList->next;
  274.             DisposPtrChk(oldSig);
  275.         }
  276.         else if (dsigList->inTemp || saveACopy) {
  277.         
  278.             // copy sig resource from temp file (or old doc file) to new document file
  279.             
  280.             if (dsigList->inTemp) {
  281.                 if (!saveACopy) {
  282.                     UseResFile(newResRef);
  283.                     newID = Unique1ID(kSignatureResType);
  284.                 }
  285.                 else
  286.                     newID = dsigList->signatureID;
  287.                 UseResFile(gDSTempRefNum);
  288.             }
  289.             else {
  290.                 newID = dsigList->signatureID;    // keep same ID for save a copy saves
  291.                 UseResFile(oldResRef);
  292.             }
  293.             resHandle = Get1Resource(kSignatureResType,dsigList->signatureID);
  294.             DetachResource(resHandle);
  295.             UseResFile(newResRef);
  296.             AddResource(resHandle,kSignatureResType,newID,"\p");
  297.             if (ResError()!=noErr) {
  298.                 DoError(ResError());
  299.                 return;
  300.             }
  301.             
  302.             // re-point objects to new ID
  303.             
  304.             if (saveACopy==false)
  305.                 dsigList->inTemp = false;
  306.             dsigList->signatureID = newID;
  307.             dsigList->shape->signatureID = newID;
  308.         }
  309.         
  310.         if (dsigList->shouldDelete==false) {
  311.             prevSig = dsigList;
  312.             dsigList = dsigList->next;
  313.         }
  314.     }
  315.     
  316.     UpdateResFile(gDSTempRefNum);
  317.     if (oldResRef)
  318.         UpdateResFile(oldResRef);    
  319.     UpdateResFile(newResRef);    
  320.     UseResFile(saveResFile);
  321. }
  322.  
  323.  
  324. /** DSIGCopySigsToTemp
  325.  **
  326.  ** needed for add/remove mailer, since this disconnects the data from the document, where
  327.  ** the signatures are stored.  this function copies all of these signature resources into the
  328.  ** temp file when the user does add or remove mailer
  329.  **/
  330. void DSIGCopySigsToTemp(WInfoPtr infoPtr)
  331. {
  332.     DigSigListPtr dsigList;
  333.     short saveResFile,docResFile;
  334.     Handle resHandle;
  335.     short newID;
  336.     
  337.     saveResFile = CurResFile();
  338.     docResFile = infoPtr->resRefNum;
  339.     
  340.     dsigList=infoPtr->otherData[kDSIGData];
  341.     while (dsigList!=nil) {
  342.         if (dsigList->inTemp==false) {
  343.             UseResFile(docResFile);
  344.             resHandle = Get1Resource(kSignatureResType,dsigList->signatureID);
  345.             DetachResource(resHandle);
  346.             UseResFile(gDSTempRefNum);
  347.             newID = Unique1ID(kSignatureResType);
  348.             AddResource(resHandle,kSignatureResType,newID,"\p");
  349.             if (ResError()!=noErr) {
  350.                 DoError(ResError());
  351.                 return;
  352.             }
  353.             dsigList->signatureID = newID;
  354.             dsigList->shape->signatureID = newID;
  355.             dsigList->inTemp = true;
  356.         }
  357.         dsigList = dsigList->next;
  358.     }
  359.     
  360.     UpdateResFile(gDSTempRefNum);
  361.     UpdateResFile(docResFile);
  362.     UseResFile(saveResFile);
  363. }
  364.  
  365.  
  366. /** DSIGDrawSigner
  367.  **
  368.  ** draws the signer outline and icon around a shape if it's signed and gShowSigners is true
  369.  **/
  370. void DSIGDrawSigner(ShapeListPtr theShape,Point drawOffset)
  371. {
  372.     Rect iconRect;
  373.     Pattern pat;
  374.     
  375.     if (!theShape->isSigned)
  376.         return;
  377.     
  378.     if (!gShowSigners)
  379.         return;
  380.         
  381.     SetRect(&iconRect,theShape->anchor.h+drawOffset.h,theShape->anchor.v+drawOffset.v,
  382.                 theShape->destination.h+drawOffset.h,theShape->destination.v+drawOffset.v);
  383.     FixRect(&iconRect);
  384.     
  385. #ifdef dangerousPattern
  386.     GetIndPattern(pat,sysPatListID,kDSIGPattern);
  387.     PenPat(pat);
  388. #else
  389.     GetIndPattern(&pat,sysPatListID,kDSIGPattern);
  390.     PenPat(&pat);
  391. #endif
  392.     PenSize(kDSIGFrameSize,kDSIGFrameSize);
  393.     FrameRect(&iconRect);
  394.     PenNormal();
  395.     
  396.     iconRect.left = iconRect.right - 16;
  397.     iconRect.top = iconRect.bottom - 16;
  398.     PlotIconID(&iconRect,atNone,ttNone,256);
  399. }
  400.  
  401.  
  402. /** DSIGHitShape
  403.  **
  404.  ** checks to see if we hit the little signature icon on this shape
  405.  **/
  406. Boolean DSIGHitShape(WInfoPtr infoPtr,Point hitPt,Point offsetPos,ShapeListPtr theShape)
  407. {
  408.     Rect dsigBox;
  409.     Boolean returnVal,hitBox;
  410.     Point mousePt;
  411.     SIGContextPtr sigContext;
  412.     OSErr err;
  413.         
  414.     SetRect(&dsigBox,theShape->anchor.h+offsetPos.h,theShape->anchor.v+offsetPos.v,
  415.                     theShape->destination.h+offsetPos.h,theShape->destination.v+offsetPos.v);
  416.     FixRect(&dsigBox);
  417.     dsigBox.left = dsigBox.right-16;
  418.     dsigBox.top = dsigBox.bottom-16;
  419.     
  420.     hitBox = false;
  421.     if (gShowSigners && PtInRect(hitPt,&dsigBox) && theShape->isSigned) {
  422.         while (WaitMouseUp()) {
  423.             GetMouse(&mousePt);
  424.             if (PtInRect(mousePt,&dsigBox)) {
  425.                 if (!hitBox) {
  426.                     hitBox = true;
  427.                     PlotIconID(&dsigBox,atNone,ttNone,257);
  428.                 }
  429.             }
  430.             else {
  431.                 if (hitBox) {
  432.                     hitBox = false;
  433.                     PlotIconID(&dsigBox,atNone,ttNone,256);
  434.                 }
  435.             }
  436.         }
  437.         PlotIconID(&dsigBox,atNone,ttNone,256);
  438.  
  439.         // verify the selected shape
  440.         
  441.         if (hitBox) {
  442.             err = SIGNewContext(&sigContext);
  443.             if (err==noErr) {
  444.                 err = VerifyShape(infoPtr,sigContext,theShape);
  445.                 SIGDisposeContext(sigContext);
  446.             }
  447.             if (err!=noErr)
  448.                 DoError(err);
  449.         }
  450.                         
  451.         returnVal = true;
  452.     }
  453.     else returnVal = false;
  454.     return returnVal;
  455. }
  456.  
  457.  
  458. /** CommSign
  459.  **
  460.  ** high level call to sign the selected shapes, called in response to "Sign Selected Shapes..."
  461.  **/
  462. void CommSign(WindowPtr window)
  463. {
  464.     WInfoPtr infoPtr;
  465.     char hState;
  466.     ShapeListPtr shapeList;
  467.     SIGContextPtr sigContext;
  468.     Size sigSize;
  469.     OSErr err;
  470.     
  471.     if (!IsAppWindow(window))
  472.         return;
  473.                 
  474.     err = SIGNewContext(&sigContext);
  475.  
  476.     if (err==noErr) {
  477.     
  478.         infoPtr = BeginWindowAccess(window,&hState);    
  479.             
  480.         if (err==noErr)
  481.             err = SIGSignPrepare(sigContext,nil,nil,&sigSize);
  482.  
  483.         for (shapeList=infoPtr->data; (err==noErr)&&(shapeList!=nil); shapeList=shapeList->next) {
  484.             if (shapeList->selected)
  485.                 err = SignShape(infoPtr,sigContext,shapeList,sigSize);
  486.                 InvalShapeArea(window,infoPtr,shapeList);
  487.         }
  488.     
  489.         SIGDisposeContext(sigContext);
  490.         DSIGSetupSignMenu(infoPtr);
  491.         EndWindowAccess(window,hState);
  492.     }
  493.     
  494.     if (err!=noErr)
  495.         DoError(err);
  496. }
  497.  
  498.  
  499. /** CommVerify
  500.  **
  501.  ** high level call to verify the selected shapes, called in response to"Verify Selected Shapes..."
  502.  **/
  503. void CommVerify(WindowPtr window)
  504. {
  505.     WInfoPtr infoPtr;
  506.     char hState;
  507.     ShapeListPtr shapeList;
  508.     SIGContextPtr sigContext;
  509.     OSErr err;
  510.         
  511.     if (!IsAppWindow(window))
  512.         return;
  513.  
  514.     err = SIGNewContext(&sigContext);
  515.     if (err==noErr) {
  516.     
  517.         infoPtr = BeginWindowAccess(window,&hState);
  518.             
  519.         for (shapeList=infoPtr->data; (err==noErr)&&(shapeList!=nil); shapeList=shapeList->next) {
  520.             if (shapeList->selected)
  521.                 err = VerifyShape(infoPtr,sigContext,shapeList);
  522.         }
  523.     
  524.         SIGDisposeContext(sigContext);
  525.         EndWindowAccess(window,hState);
  526.     }
  527.     
  528.     if (err!=noErr)
  529.         DoError(err);
  530. }
  531.  
  532.  
  533. /** CommShowSigners
  534.  **
  535.  ** shows or hides the signer icons/outlines in any signed shapes
  536.  **/
  537. void CommShowSigners(WindowPtr window)
  538. {
  539.     WInfoPtr infoPtr;
  540.     char hState;
  541.     ShapeListPtr shapeList;
  542.     
  543.     if (!IsAppWindow(window))
  544.         return;
  545.     
  546.     infoPtr = BeginWindowAccess(window,&hState);
  547.  
  548.     gShowSigners = !gShowSigners;
  549.  
  550.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  551.         if (shapeList->isSigned)
  552.             InvalShapeArea(window,infoPtr,shapeList);
  553.     }
  554.  
  555.     DSIGSetupSignMenu(infoPtr);
  556.     
  557.     EndWindowAccess(window,hState);
  558. }
  559.  
  560.  
  561. /*----------------------------------------------------------------------------------------------*/
  562. /* local calls inside this file                                                                    */
  563. /*----------------------------------------------------------------------------------------------*/
  564.  
  565. /** SignShape
  566.  **
  567.  ** signs a given shape using the passed in context and required signature size
  568.  **/
  569. OSErr SignShape(WInfoPtr infoPtr,SIGContextPtr sigContext,ShapeListPtr theShape,Size sigSize)
  570. {
  571.     OSErr err;
  572.     Handle signature;
  573.     short resID;
  574.     short saveResFile;
  575.     DigSigListPtr theSig;
  576.     
  577.     // allocate storage for the signature
  578.     
  579.     signature = NewHandleChk(sigSize);
  580.     if (MemError()!=noErr)
  581.         return MemError();
  582.     
  583.     // process the data for the signature
  584.     
  585.     err = ProcessShapeData(sigContext,theShape);
  586.         if (err!=noErr) {
  587.         DisposHandleChk(signature);
  588.         return err;
  589.     }
  590.     
  591.     // create the signature
  592.     
  593.     HLock(signature);
  594.     err = SIGSign(sigContext,(SIGSignaturePtr)*signature,nil);
  595.     HUnlock(signature);
  596.     
  597.     // bail if the sign didn't succeed
  598.     
  599.     if (err!=noErr)
  600.         return err;
  601.         
  602.     // add the signature to the shape
  603.     
  604.     saveResFile = CurResFile();
  605.     UseResFile(gDSTempRefNum);
  606.     resID = Unique1ID(kSignatureResType);
  607.     AddResource(signature,kSignatureResType,resID,"\p");
  608.     if (ResError()==noErr) {
  609.  
  610.         ReleaseResource(signature);
  611.  
  612.         // see if old shape is already signed-- if so, mark the old signature for deletion
  613.         
  614.         if (theShape->isSigned) {
  615.             theSig = theShape->digSig;
  616.             theSig->shouldDelete = true;
  617.         }
  618.         
  619.         // create the signature object and add it to the list, ref to shape
  620.         
  621.         theSig = NewPtrChk(sizeof(DigSigList));
  622.         if (MemError()!=noErr)
  623.             return MemError();
  624.         theSig->shape = theShape;
  625.         theSig->inTemp = true;
  626.         theSig->shouldDelete = false;
  627.         theSig->next = infoPtr->otherData[kDSIGData];
  628.         infoPtr->otherData[kDSIGData] = theSig;
  629.         theSig->signatureID = resID;
  630.  
  631.         theShape->digSig = theSig;
  632.         theShape->signatureID = resID;
  633.         theShape->isSigned = true;
  634.     }
  635.     else {
  636.         DisposHandleChk(signature);
  637.         err = ResError();
  638.     }
  639.     UpdateResFile(gDSTempRefNum);
  640.     UseResFile(saveResFile);
  641.  
  642.     return err;
  643. }
  644.  
  645.  
  646. /** VerifyShape
  647.  **
  648.  ** verifies a given shape using the passed in context
  649.  **/
  650. OSErr VerifyShape(WInfoPtr infoPtr,SIGContextPtr sigContext,ShapeListPtr theShape)
  651. {
  652.     DigSigListPtr theSig;
  653.     short saveResFile;
  654.     Handle sigHandle;
  655.     OSErr err;
  656.     Size signatureSize;
  657.     
  658.     if (theShape->isSigned==false)
  659.         return noErr;
  660.         
  661.     theSig = theShape->digSig;
  662.     
  663.     saveResFile = CurResFile();
  664.     if (theSig->inTemp)
  665.         UseResFile(gDSTempRefNum);
  666.     else
  667.         UseResFile(infoPtr->resRefNum);
  668.     sigHandle = Get1Resource(kSignatureResType,theSig->signatureID);
  669.     err = ResError();
  670.     UseResFile(saveResFile);
  671.     if (err!=noErr)
  672.         return err;
  673.         
  674.     signatureSize = SizeResource(sigHandle);
  675.     HLock(sigHandle);
  676.     err = SIGVerifyPrepare(sigContext,(SIGSignaturePtr)*sigHandle,signatureSize,nil);
  677.     if (err==noErr) {
  678.     
  679.         // process the data for the signature
  680.         err = ProcessShapeData(sigContext,theShape);
  681.         if (err==noErr) {
  682.             err = SIGVerify(sigContext);
  683.             if (err==noErr)
  684.                 err = SIGShowSigner(sigContext,nil);
  685.         }
  686.     }
  687.     
  688.     ReleaseResource(sigHandle);
  689.     return err;
  690. }
  691.  
  692.  
  693. /** ProcessShapeData
  694.  **
  695.  ** digests the shape data for the signature.  may be called recursively for group shapes
  696.  **/
  697. OSErr ProcessShapeData(SIGContextPtr sigContext,ShapeListPtr theShape)
  698. {
  699.     OSErr err;
  700.     ShapeListPtr shapeList;
  701.     
  702.     err = noErr;
  703.     if (theShape->shapeType==kBeginGroupTag) {
  704.         for (shapeList=theShape->subList; (shapeList!=nil) && (err==noErr);
  705.                 shapeList=shapeList->next)
  706.             err = ProcessShapeData(sigContext,shapeList);
  707.     }
  708.     else
  709.         err = SIGProcessData(sigContext,theShape,kShapeSignLength);
  710.     return err;
  711. }